using System.Diagnostics;
using System.Text.Json.Serialization;
using JetBrains.Annotations;
using SageKing.Designer.Core.Contracts;
using SageKing.Designer.Core.Converters;
using SageKing.Designer.Core.Helpers;

namespace SageKing.Designer.Core;

/// <summary>
/// Base class for custom activities.
/// </summary>
[DebuggerDisplay("{Type} - {Id}")]
[UsedImplicitly(ImplicitUseTargetFlags.WithInheritors | ImplicitUseTargetFlags.Members)]
public abstract class Activity : IActivity
{
    /// <summary>
    /// Constructor.
    /// </summary>
    protected Activity(string? source = default, int? line = default)
    {
        this.SetSource(source, line);
        Type = ActivityTypeNameHelper.GenerateTypeName(GetType());
        Version = 1;
    }

    /// <inheritdoc />
    protected Activity(string activityType, int version = 1, string? source = default, int? line = default) : this(source, line)
    {
        Type = activityType;
        Version = version;
    }

    /// <inheritdoc />
    public string Id { get; set; } = default!;

    /// <inheritdoc />
    public string NodeId { get; set; } = default!;

    /// <inheritdoc />
    public string? Name { get; set; }

    /// <inheritdoc />
    public string Type { get; set; }

    /// <inheritdoc />
    public int Version { get; set; }

    /// <summary>
    /// A flag indicating whether this activity can be used for starting a workflow.
    /// Usually used for triggers, but also used to disambiguate between two or more starting activities and no starting activity was specified.
    /// </summary>
    [JsonIgnore]
    public bool CanStartWorkflow
    {
        get => this.GetCanStartWorkflow();
        set => this.SetCanStartWorkflow(value);
    }

    /// <summary>
    /// A flag indicating if this activity should execute synchronously or asynchronously.
    /// By default, activities with an <see cref="ActivityKind"/> of <see cref="Action"/>, <see cref="Task"/> or <see cref="Trigger"/>
    /// will execute synchronously, while activities of the <see cref="ActivityKind.Job"/> kind will execute asynchronously.
    /// </summary>
    [JsonIgnore]
    public bool RunAsynchronously
    {
        get => this.GetRunAsynchronously();
        set => this.SetRunAsynchronously(value);
    }

    /// <inheritdoc />
    [JsonConverter(typeof(PolymorphicObjectConverterFactory))]
    public IDictionary<string, object> CustomProperties { get; set; } = new Dictionary<string, object>();

    /// <inheritdoc />
    [JsonIgnore]
    public IDictionary<string, object> SyntheticProperties { get; set; } = new Dictionary<string, object>();

    /// <inheritdoc />
    [JsonConverter(typeof(PolymorphicObjectConverterFactory))]
    public IDictionary<string, object> Metadata { get; set; } = new Dictionary<string, object>(); 

}